package goft

import (
	"fmt"
	"reflect"
)

type BeanFactory struct {
	beans []interface{}
}

func NewBeanFactory() *BeanFactory {
	bf := &BeanFactory{beans: make([]interface{}, 0)}
	//放入 工厂内
	bf.beans = append(bf.beans, bf)
	return bf
}

/**
SetBean 设置bean 如:gorm之类的
*/
func (bf *BeanFactory) SetBean(object ...interface{}) {
	//for _, item := range object {
	//	bf.Inject(item)
	//}
	bf.beans = append(bf.beans, object...)
}

/**
GetBean 获取
*/
func (bf *BeanFactory) GetBean(object interface{}) interface{} {
	return bf.getBean(reflect.TypeOf(object))
}

func (bf *BeanFactory) getBean(p reflect.Type) interface{} {
	for _, b := range bf.beans {
		b_ref := reflect.TypeOf(b)
		if b_ref == p {
			return b
		}
	}
	return nil
}

func (bf *BeanFactory) Inject(obejct interface{}) {
	//反射-结构体
	v_ref := reflect.ValueOf(obejct)
	t_ref := reflect.TypeOf(obejct)
	//判断是否 指针类型
	if v_ref.Kind() == reflect.Ptr {
		v_ref = v_ref.Elem()
	}
	for i := 0; i < v_ref.NumField(); i++ {
		p := v_ref.Field(i)
		if p.Kind() != reflect.Ptr || p.IsNil() {
			continue
		}

		//判断是否注解
		if IsAnnotation(p.Type()) {
			//反射 设置注解类型
			p.Set(reflect.New(p.Type()).Elem())
			p.Interface().(Annotation).SetTag(t_ref.Field(i).Tag)
			bf.Inject(p.Interface())
			continue
		}

		//如果工厂中有 当前p.Type类型 赋值 注入
		if f := bf.getBean(p.Type()); f != nil && p.CanInterface() {
			p.Set(reflect.New(p.Type()).Elem())
			p.Elem().Set(reflect.ValueOf(f).Elem())
		}
	}
}

/**
inject 内部调用
*/
func (bf *BeanFactory) inject(class IClass) {
	v_ref := reflect.ValueOf(class).Elem()
	t_ref := reflect.TypeOf(class).Elem()
	for i := 0; i < v_ref.NumField(); i++ {
		f := v_ref.Field(i)
		if f.Kind() != reflect.Ptr {
			continue
		}
		if IsAnnotation(f.Type()) {
			//反射 设置注解类型
			f.Set(reflect.New(f.Type()).Elem())
			f.Interface().(Annotation).SetTag(t_ref.Field(i).Tag)
			bf.Inject(f.Interface())
			continue
		}
		if p := bf.getBean(f.Type()); p != nil {
			fmt.Println(f.Type().Elem())
			f.Set(reflect.New(f.Type().Elem()))
			f.Elem().Set(reflect.ValueOf(p).Elem())
		}
	}

}
